/**
 * @brief 2.4.4 常量表达式
 * 常量表达式指：值不会改变，且在编译过程就能得到计算结果的表达式
 * 字面值属于常量表达式，用常量表达式初始化的const对象也是常量表达式
 * @param argc 
 * @param argv 
 * @return int 
 */

int get_size();

// int size();
// int size()
// {
//     return 1;
// }
constexpr int size();
constexpr int size()
{
    return 1 + 1;
}

int cb = 500; // 定义于所有函数体之外的对象其地址固定不变
constexpr int *const pcb = &cb; // 定义于所有函数体之外的对象其地址固定不变，能用来初始化constexpr指针。

int main(int argc, char const *argv[])
{
    const int max_files = 20; // max_files是常量表达式
    const int limit = max_files + 1; // limit是常量表达式
    int staff_size = 27; // satff_size不是常量表达式
    const int sz = get_size(); // sz不是常量表达式

    // 允许将变量声明为constexpr类型，以便由编译器来验证变量的值是否是一个常量表达式
    constexpr int mf = 20; // 20是一个常量表达式
    constexpr int limit1 = mf + 1; // mf+1是个常量表达式
    constexpr int sz1 = size(); // 只有当size是个constexpr函数时，才是一条正确的声明语句，否则会报错

    // 函数体内定义的变量一般来说并非存放在固定地址中，因此constexpr指针不能指向这样的变量
    // 定义于所有函数体之外的对象其地址固定不变，能用来初始化constexpr指针。
    constexpr int *pcb1 = &cb; // pcb1是一个指向cb的常量指针
    // 在constexpr声明中如果定义了一个指针，限定符constexpr仅对指针有效

    // 下面两者的类型相差甚远
    const int *p = nullptr; // p是一个指向整型常量的指针
    constexpr int *q = nullptr; // q是一个指向整数的常量指针

    constexpr const int *b = nullptr; // b是一个指向整型常量的常量指针

    return 0;
}

int get_size()
{
    return 1+1;
}

